/*
 * Ex:			
 * File name:   user_thread.cpp
 *
 *  Created on: Apr 3, 2012
 *      Author: ayash
 *
 *
 * Descriptor:
 *
 */

#include <cstring>
#include <cassert>
#include "user_thread.h"


UserThread:: UserThread ( uint id, uint priority ):
_state(THREAD_STATE_UNDEFIEND), _priority(priority), _id(id)
{
	DBG_PRINT("UserThread Creation: ID = %u\t priority = %u\n", id, priority);
}

UserThread:: ~UserThread()
{
	DBG_PRINT("UserThread Destruction: ID = %u\t priority = %u\n", _id, _priority);
}

thread_state_t UserThread:: get_thread_state() const { return _state; }

result_t UserThread:: set_thread_state(thread_state_t new_state)
{
	assert ( _state != new_state );

	_state = new_state;

	if ( THREAD_STATE_READY == _state )
	{
		return set_ready_time();
	}

	return OPERATION_SUCCESS;
}

uint UserThread:: get_thread_id() const { return _id; }

uint UserThread:: get_thread_priority() const { return _priority; }

uint UserThread:: set_thread_priority(uint new_priority)
{
	uint prev_priority = _priority;;

	DBG_PRINT("UserThread:: Setting thread ID: %d from priority %d to priority %d.\n",
			  _id,
			  prev_priority,
			  new_priority);

	_priority = new_priority;

	return prev_priority;
}

char* UserThread:: get_stack_addr() { return _stack; }

sigjmp_buf* UserThread:: get_thread_jmp_buffer() { return & _jbuf; }

const timeval* UserThread:: get_ready_time() const
{
	return & _last_time;
}

void UserThread:: set_thread_u_area( sigjmp_buf *jbuf )
{
	assert( NULL != jbuf );

	// copy the given u_area
	memcpy( & _jbuf , jbuf, sizeof(_jbuf) );
}

inline result_t UserThread::set_ready_time()
{
	int ret_code = gettimeofday( & _last_time, NULL );

	return ( ! ret_code ) ? OPERATION_SUCCESS : ERROR_SYSTEM_CALL;
}

// return false if the lhs have higher priority (should be schedule before rhs)
bool ThreadsComparator:: operator ()( const UserThread*  lhs, const UserThread* rhs )
{
	uint lhs_priprity, rhs_priority;

	assert( NULL != lhs && NULL != rhs );

	lhs_priprity = lhs-> get_thread_priority();
	rhs_priority = rhs-> get_thread_priority();

	if ( MIN_VAL_PRIORITY == lhs_priprity )
	{
		return false;
	}

	if( MIN_VAL_PRIORITY == rhs_priority )
	{
		return true;
	}

	if ( lhs_priprity < rhs_priority  )
	{
		return false;
	}

	if ( lhs_priprity > rhs_priority )
	{
		return true;
	}

	// the two threads has the same priority

	// in case one of them is running it shouldn't be preempted
	if ( THREAD_STATE_RUNNING == lhs->get_thread_state() )
	{
		return false;
	}

	if ( THREAD_STATE_RUNNING ==  rhs->get_thread_state() )
	{
		return true;
	}

	// compare their ready time
	if ( timercmp( lhs->get_ready_time() , rhs->get_ready_time(), < ) )
	{
		return false;
	}

	if ( timercmp( lhs->get_ready_time() , rhs->get_ready_time(), > ) )
	{
		return true;
	}

	/*
	 * the threads has the same priority and same ready time - this can only happen
	 * during creation of two consecutive threads so we compare their id.
	 */
	return !(lhs->get_thread_id() < rhs->get_thread_id()) ;

}
